package day03;

import java.nio.charset.StandardCharsets;
import java.util.Arrays;

public class UTF8 {
    /**
     * 将字符串编码为UTF-8字节
     * @param str 被编码的字符
     * @return UTF-8编码的字节
     */
    public static byte[] encode(String str){
        /*
         * 遍历每个字符, 将字符按照范围进行编码
         * 0 ~ 0x7f 范围单字节编码
         * 0x80~ 0x7ff 范围 双字节编码
         * 0x800 ~ 0xffff 三字节编码
         */
        // String str = "Javaλ表达式" 4+2+9 = 15 字节
        // 假设最坏情况 每个字符转换为3个字节
        byte[] bytes = new byte[str.length() * 3];
        // 返回值之前, 将数组缩容即可
        int index = 0;
        for (int i = 0; i<str.length(); i++){
            //c 就是 字符串的Unicode编码
            char c = str.charAt(i);
            if (c < 0x80) { //0 ~ 0x7f 范围单字节编码
                byte b = (byte) c;
                bytes[index++] = b;
            } else if ( c < 0x800 ){ //0x80 ~ 0x7ff 范围双字节编码
                byte b1 = (byte) ((c>>>6) | 0xc0);
                byte b2 = (byte) ((c & 0x3f) | 0x80);
                bytes[index++] = b1;
                bytes[index++] = b2;
            } else if (c < 0x10000) { //0x800 ~ 0xffff 范围双字节编码
                byte b1 = (byte) ((c>>>12) | 0xe0);
                byte b2 = (byte) (((c>>>6) & 0x3f) | 0x80);
                byte b3 = (byte) ((c & 0x3f) | 0x80);
                bytes[index++] = b1;
                bytes[index++] = b2;
                bytes[index++] = b3;
            }
        }
        return Arrays.copyOf(bytes, index);
    }

    /**
     * 将UTF-8字节解码为字符串
     * @param bytes UTF-8字节
     * @return 解码以后的字符串
     */
    public static String decode(byte[] bytes){
        //先检查第一个字节，如果是
        // 0开头就是单字节编码
        // 110 开头就是双字节编码
        // 1110 开头就是三字节编码
        char[] chs = new char[bytes.length];
        int index = 0;
        for(int i=0; i<bytes.length;){
            int b1 = bytes[i++] & 0xff; //01110110
            if ((b1 >>> 7) == 0){ //高位为0, 单字节编码
                char c = (char)b1;
                chs[index++] = c;
            } else if ((b1 >>> 5) == 0b110){ //高位是 110, 双字节编码
                int b2 = bytes[i++] & 0xff;
                char c = (char) (((b1 & 0x1f) << 6) | (b2 & 0x3f));
                chs[index++] = c;
            } else if ((b1 >>> 4) == 0b1110){//高位是 1110, 3字节编码
                int b2 = bytes[i++] & 0xff;
                int b3 = bytes[i++] & 0xff;
                char c = (char) (((b1 & 0xf) << 12) |
                                ((b2 & 0x3f) << 6) | (b3 & 0x3f) );
                chs[index++] = c;
            }
        }
        return new String(chs, 0, index);
    }

    public static void main(String[] args) {
        String str = "Javaλ表达式";
        byte[] bytes = encode(str);
        for (byte b:bytes){
            System.out.println(Integer.toBinaryString(b & 0xff));
        }
        String s = new String(bytes, StandardCharsets.UTF_8);
        System.out.println(s);
        System.out.println(decode(bytes));
    }
}

